#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：NoBad
@File    ：view.py
@Author  ：LYP
@Date    ：2025/10/30 13:26
@description :小程序相关函数
"""
import json
import random
import time
import requests
import uuid

from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import transaction
from datetime import datetime
from django.http import JsonResponse
from django.forms import model_to_dict
from django.views.decorators.http import require_http_methods
from rest_framework.decorators import api_view, action
from rest_framework.views import APIView
from rest_framework import serializers
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiParameter

from App.view.poster.view import PosterSerializer
from models.models import WeChatUser as ChatUser, Product, WeChatPayOrder as Order, InvitationRecord
from models.models import WeChatUser
from tool.permissions import IsTokenValid
from tool.tools import getEnvConfig, logger, res, CustomStatus
from tool.token_tools import CustomTokenTool, _redis
from tool.tool_wechat import getWechatAccessToken, checkWechatUserIsExist, genterateWechatAuth, decryptData, \
    updataOrderNotify, generateSign
from tool.utils import CustomPagination, ApiResponse
from tool.base_views import BaseViewSet
from django.utils.translation import gettext as _
is_token = IsTokenValid()


@extend_schema(
    methods=['POST'],
    tags=["微信接口"],
    summary="微信登陆byOpenId",
    description="通过微信授权码获取用户openId和session_key",
    request={
        'application/json': {
            'type': 'object',
            'properties': {
                'code': {'type': 'string', 'description': '微信登录授权码'},
                'inviter_openid': {'type': 'string', 'description': '邀请人openid（可选）'}
            },
            'required': ['code']
        }
    },
    responses={
        200: {
            'description': '成功获取openId',
            'content': {
                'application/json': {
                    'schema': {
                        'type': 'object',
                        'properties': {
                            'code': {'type': 'integer', 'example': 200},
                            'message': {'type': 'string', 'example': '登录成功'},
                            'data': {
                                'type': 'object',
                                'properties': {
                                    'openid': {'type': 'string', 'example': 'oO2lj5PjHbG4xxxxxx'},
                                    'token': {'type': 'string',
                                              'example': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.xxxxxx'}
                                }
                            }
                        }
                    }
                }
            }
        },
        400: {
            'description': '获取openId失败'
        }
    }
)
@api_view(['POST'])
def getWechatOpenId(request):
    """
    微信登陆byOpenId
    :param request:
    :return:
    """
    res.clear()
    try:
        if request.method == 'POST':
            body = json.loads(request.body)
            code = body.get('code')
            inviter_openid = body.get('inviter_openid')  # 获取邀请人openid
            if not code:
                return JsonResponse(CustomStatus.WECHAT_CODE_INVALID.to_response())
            base_url = getEnvConfig("WECHAT_BASE_URL")
            end_path = getEnvConfig("LOGIN_END_PATH")
            appId = getEnvConfig("APPID")
            appSecret = getEnvConfig("APPSECRET")
            login_url = base_url + end_path.format(appId, appSecret, code)
            response = requests.get(login_url).json()
            if "openid" in response.keys():
                openId = response.get("openid")
                session_key = response.get("session_key")
                token = CustomTokenTool.generate_token(openId)
                user_exists = WeChatUser.objects.filter(open_id=openId).exists()
                user = checkWechatUserIsExist(openId, session_key, "create")
                is_new_user = False
                if not user_exists and inviter_openid:
                    try:
                        inviter = WeChatUser.objects.get(open_id=inviter_openid)
                        InvitationRecord.objects.get_or_create(
                            invitee=user, # 自己被谁邀请的
                            defaults={'inviter': inviter}  # 被这个人邀请的 点击者
                        )
                        is_new_user = True
                        if is_new_user:
                            old_count = inviter.share_success_count
                            inviter.share_success_count = old_count + 1
                            count = int(getEnvConfig("Is_Actice_count"))
                            if inviter.share_success_count % count == 0:
                                # 重置分享计数
                                inviter.share_success_count = 0
                                # allow_count加1（处理None的情况）
                                inviter.allow_count = (inviter.allow_count or 0) + 1
                            inviter.save()

                    except WeChatUser.DoesNotExist:
                        # 邀请人不存在，记录日志但不影响正常登录流程
                        logger.warning(f"邀请人 {inviter_openid} 不存在")
                return JsonResponse(CustomStatus.WECHAT_LOGIN_SUCCESS.to_response(
                    {"openid": openId, "token": token, "is_new": is_new_user}))
            else:
                return JsonResponse(
                    CustomStatus.WECHAT_INFO_FETCH_FAILED.custom_message(status=CustomStatus.WECHAT_INFO_FETCH_FAILED,
                                                                         custom_msg=response.get("errmsg")))
    except Exception as e:
        logger.error(f"获取微信openId失败: {str(e)}")
        return JsonResponse(CustomStatus.WECHAT_OPENID_ERROR.to_response())


@extend_schema(
    methods=['POST'],
    tags=["微信接口"],
    summary="获取用户手机号",
    description="通过微信授权码获取用户手机号",
    request={
        'application/json': {
            'type': 'object',
            'properties': {
                'code': {'type': 'string', 'description': '微信授权码'},
                'openId': {'type': 'string', 'description': '用户openId'}
            },
            'required': ['code', 'openId']
        }
    },
    responses={
        200: {
            'description': '成功获取手机号',
            'content': {
                'application/json': {
                    'schema': {
                        'type': 'object',
                        'properties': {
                            'code': {'type': 'integer', 'example': 200},
                            'message': {'type': 'string', 'example': '获取成功'},
                            'data': {
                                'type': 'object',
                                'properties': {
                                    'phone': {'type': 'string', 'example': '13800138000'}
                                }
                            }
                        }
                    }
                }
            }
        },
        400: {
            'description': '获取手机号失败'
        }
    }
)
@api_view(['POST'])
def getUserPhone(request):
    """
    获取用户手机号
    :param request:
    :return:
    """
    res.clear()
    is_token_result = is_token.has_permission(request, None)
    if not is_token_result:
        return JsonResponse(CustomStatus.UNAUTHORIZED.to_response())
    try:
        if request.method == "POST":
            body = json.loads(request.body)
            code = body.get("code")
            openId = body.get("openId")
            base_url = getEnvConfig("WECHAT_BASE_URL")
            end_path = getEnvConfig("GET_USER_PHONE_END_PATH")
            access_token = getWechatAccessToken()
            url = base_url + end_path.format(access_token)
            response = requests.post(url, json={"code": code}).json()
            if "phone_info" in response.keys():
                phoneInfo = response["phone_info"]
                phoneNumber = phoneInfo["purePhoneNumber"]
                checkWechatUserIsExist(openId=openId, session_key="", types="update", phone=phoneNumber)
                return JsonResponse(CustomStatus.WECHAT_PHONE_SUCCESS.to_response({"phone": phoneNumber}))
            else:
                return JsonResponse(
                    CustomStatus.WECHAT_PHONE_ERROR.custom_message(status=CustomStatus.WECHAT_PHONE_ERROR,
                                                                   custom_msg=response["errmsg"]))
    except Exception as e:
        logger.error(f"获取微信手机号失败: {str(e)}")
        return JsonResponse(CustomStatus.WECHAT_PHONE_ERROR.to_response())


@extend_schema(
    tags=["微信接口"],  # 文档中的标签（与类视图分组一致）
    summary="获取用户信息",  # 接口摘要
    description="通过 Token 验证后，获取当前登录用户的详细信息",  # 接口描述
    methods=['GET'],  # 支持的请求方法（GET/POST 等）
    # 可选：定义请求参数（如 Query 参数）
    parameters=[
        # 示例：如果需要用户 ID 作为参数
        # OpenApiParameter(name="user_id", type=int, location=OpenApiParameter.QUERY, description="用户 ID")
    ],
    # 可选：定义响应格式
    responses={
        200: {
            "type": "object",
            "properties": {
                "user_id": {"type": "integer"},
                "username": {"type": "string"},
                "email": {"type": "string"}
            }
        }
    },
)
@api_view(['GET'])
def getUserInfo(request):
    """
    获取用户信息
    :param request:
    :return:
    """
    res.clear()
    try:
        if request.method == "GET":
            openId = request.GET.get("openId")
            try:
                data = ChatUser.objects.get(open_id=openId)
                return JsonResponse(CustomStatus.GET_USER_INFO_SUCCESS.to_response(model_to_dict(data)))
            except ChatUser.DoesNotExist:
                return JsonResponse(
                    CustomStatus.GET_USER_INFO_ERROR.custom_message(status=CustomStatus.GET_USER_INFO_ERROR,
                                                                    custom_msg=_("用户不存在")))
    except Exception as e:
        logger.error(f"获取用户信息失败: {str(e)}")
        return JsonResponse(CustomStatus.GET_USER_INFO_ERROR.to_response())


@extend_schema(
    methods=['POST'],
    tags=["微信接口"],
    summary="更新用户信息",
    description="更新用户的昵称和头像信息",
    request={
        'application/json': {
            'type': 'object',
            'properties': {
                'openId': {'type': 'string', 'description': '用户openId'},
                'username': {'type': 'string', 'description': '用户昵称'},
                'user_avatar': {'type': 'string', 'description': '用户头像URL'}
            },
            'required': ['openId']
        }
    },
    responses={
        200: {
            'description': '更新成功',
            'content': {
                'application/json': {
                    'schema': {
                        'type': 'object',
                        'properties': {
                            'code': {'type': 'integer', 'example': 200},
                            'message': {'type': 'string', 'example': '更新成功'}
                        }
                    }
                }
            }
        },
        400: {
            'description': _('更新失败')
        }
    }
)
@api_view(['POST'])
@transaction.atomic
def updataUserInfo(request):
    """
    更新用户信息
    :param request:
    :return:
    """
    res.clear()
    try:
        # result = is_token.has_permission(request, None)
        # if not result:
        #     return JsonResponse(CustomStatus.UNAUTHORIZED.to_response())
        if request.method == "POST":
            body = json.loads(request.body)
            openId = body.get("openId")
            username = body.get("username")
            user_avatar = body.get("user_avatar")
            user_gender = body.get("user_gender")
            data = ChatUser.objects.get(open_id=openId)
            if username:
                data.username = username
            if user_avatar:
                data.user_avatar = user_avatar
            if user_gender:
                data.user_gender = user_gender
            data.save()
            return JsonResponse(CustomStatus.UPDATA_USER_INFO_SUCCESS.to_response())
    except Exception as e:
        logger.error(f"更新用户信息失败: {str(e)}")
        return JsonResponse(CustomStatus.UPDATA_USER_INFO_ERROR.to_response())


@extend_schema(
    methods=['POST'],
    tags=["微信接口"],
    summary="获取预支付订单",
    description="创建微信支付预支付订单，获取prepay_id",
    request={
        'application/json': {
            'type': 'object',
            'properties': {
                'description': {'type': 'string', 'description': '商品描述'},
                'productId': {'type': 'integer', 'description': '商品ID'},
                'openId': {'type': 'string', 'description': '用户openId'},
                'posterId': {'type': 'integer', 'description': '海报ID'}
            },
            'required': ['description', 'productId', 'openId']
        }
    },
    responses={
        200: {
            'description': '成功创建预支付订单',
            'content': {
                'application/json': {
                    'schema': {
                        'type': 'object',
                        'properties': {
                            'code': {'type': 'integer', 'example': 200},
                            'message': {'type': 'string', 'example': '创建成功'},
                            'data': {
                                'type': 'object',
                                'properties': {
                                    'prepay_id': {'type': 'string', 'example': 'wx1234567890abcdef1234567890abcdef'}
                                }
                            }
                        }
                    }
                }
            }
        },
        400: {
            'description': '创建预支付订单失败'
        }
    }
)
@api_view(['POST'])
def getPrepayId(request):
    """
    获取预支付订单
    :param request:
    :return:
    """
    res.clear()
    result = is_token.has_permission(request, None)
    if not result:
        return JsonResponse(CustomStatus.UNAUTHORIZED.to_response())
    try:
        if request.method == "POST":
            body = json.loads(request.body)
            logger.info(f"预支付订单参数为===》{body}")
            base_url = getEnvConfig("WECHAT_PAY_BASE_URL")
            end_path = getEnvConfig("WECHAT_PAY_JSAPI_METHOD")
            url = f"{base_url}{end_path}"
            appid = getEnvConfig("APPID")
            mchid = getEnvConfig("WECHAT_MCHID")
            notify_url = getEnvConfig("WECHAT_NOTIFY_URL")
            description = body.get("description")
            productId = body.get("productId")
            posterId = body.get("posterId")
            logger.info(f"商品描述为==》{description}=======liang===")
            logger.info(f"商品ID为==》{productId}=======liang===")
            logger.info(f"海报ID为==》{posterId}=======liang===")
            openid = body.get("openId")
            product = Product.objects.get(id=productId)
            user = ChatUser.objects.get(open_id=openid)
            nonceStr = str(random.randint(100000, 10000000))
            timestamp = str(int(time.time()))
            out_trade_no = str(uuid.uuid4()).replace('-', '')
            data = {"appid": appid, "mchid": mchid, "description": description, "out_trade_no": out_trade_no,
                    "attach": json.dumps({
                        "productId": str(product.id),
                        "posterId": str(posterId)
                    }), "notify_url": notify_url,
                    "amount": {"total": int(product.price * 100), "currency": "CNY"},
                    "payer": {"openid": openid}}
            dump_data = json.dumps(data, ensure_ascii=False, indent=2)
            logger.info(f"url:{url}\ndata:{data}")
            logger.info(f"请求包体参数==》{dump_data}")
            Authorization = genterateWechatAuth(dump_data, nonceStr, timestamp)
            headers = {"Accept": "application/json", "Content-Type": "application/json", "Authorization": Authorization}
            respone = requests.post(url, data=dump_data, headers=headers).json()
            logger.info(f"响应参数==》{respone}")
            Order.objects.create(out_trade_no=out_trade_no, openid=openid, product_name=product.name,
                                 mch_id=mchid, appid=appid, trade_state="NOTPAY", created_time=datetime.now(),
                                 is_notify_processed=False, product_id=product.id, posterId=posterId, payer_id=user.id)
            if "prepay_id" in respone.keys():
                prepay_id = respone["prepay_id"]
                logger.info(f"prepay_id:{prepay_id}")
                sign = generateSign(timestamp, nonceStr, prepay_id)
                logger.info(f"sign:{sign}")
                resData = {
                    "appId": appid,
                    "noncestr": nonceStr,
                    "prepayid": f"prepay_id={prepay_id}",
                    "paySign": sign,
                    "timeStamp": timestamp,
                    "partnerid": mchid
                }
                return JsonResponse(CustomStatus.SUCCESS.to_response(resData))
            else:
                return JsonResponse(
                    CustomStatus.BAD_REQUEST.custom_message(status=CustomStatus.BAD_REQUEST,
                                                            custom_msg=respone["message"]))

    except Exception as e:
        logger.error(f"获取微信预支付订单失败")
        return JsonResponse(CustomStatus.BAD_REQUEST.custom_message(status=CustomStatus.BAD_REQUEST, custom_msg=str(e)))

def getNotrify(request):
    """
    获取微信支付回调
    :param request:
    :return:
    """
    res.clear()
    try:
        if request.method == "POST":
            body = json.loads(request.body)
            logger.info(f"微信支付回调参数为==》{body}")
            resData = body.get('resource')
            ciphertext = resData['ciphertext']
            associatedData = resData['associated_data']
            nonce = resData['nonce']
            logger.info(f"参数数据==》{ciphertext, associatedData, nonce}")
            data = decryptData(nonce, ciphertext, associatedData)
            updataOrderNotify(data)
            return JsonResponse(CustomStatus.SUCCESS.to_response())
    except Exception as e:
        logger.error(f"获取微信支付回调失败: {str(e)}")
        return JsonResponse(CustomStatus.BAD_REQUEST.custom_message(status=CustomStatus.BAD_REQUEST, custom_msg=str(e)))


class WechatUserSerializer(serializers.ModelSerializer):
    """
    微信支付订单序列化器
    """
    open_id = serializers.CharField(required=False)
    nick_name = serializers.CharField(required=False)
    status_display = serializers.SerializerMethodField()

    class Meta:
        model = WeChatUser
        fields = '__all__'

    def get_status_display(self, obj):
        """获取状态显示名称"""
        return obj.get_status_display()


@extend_schema(tags=["微信支付订单"])
@extend_schema_view(
    list=extend_schema(summary="获取微信用户",
                       parameters=[OpenApiParameter(
                           name='search',
                           description='搜索参数（可按用户ID或用户名搜索）',
                           required=False,
                           type=str
                       ),
                       ], responses={200: WechatUserSerializer(many=True), }),
    retrieve=extend_schema(summary="获取微信用户详情",
                           responses={200: WechatUserSerializer, 404: "用户不存在"}),
    update=extend_schema(
        summary="更新微信用户", request=WechatUserSerializer),
    destroy=extend_schema(summary="删除微信用户", description="删除指定用户，仅管理员可操作",
                          responses={204: "删除成功", 404: "用户不存在"}
                          )
)
class WxUserViewSet(BaseViewSet):
    queryset = ChatUser.objects.all()
    serializer_class = WechatUserSerializer
    pagination_class = CustomPagination

    def get_queryset(self):
        queryset = super().get_queryset()
        search_param = self.request.query_params.get('search')
        if search_param:
            # 如果搜索参数是数字，按ID搜索；否则按用户名搜索
            if search_param.isdigit():
                queryset = queryset.filter(id=int(search_param))
            else:
                queryset = queryset.filter(username__icontains=search_param)
        return queryset

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            # 使用自定义分页响应
            return self.get_paginated_response(serializer.data)
        # 如果没有分页，返回普通响应
        serializer = self.get_serializer(queryset, many=True)
        return ApiResponse(serializer.data)

    def update(self, request, *args, **kwargs):
        try:
            logger.info(f"Update request for pk: {kwargs.get('pk')}")
            logger.info(f"Request data: {request.data}")
            instance = self.get_object()
            serializer = self.get_serializer(instance, data=request.data)
            serializer.is_valid(raise_exception=True)
            self.perform_update(serializer)
            return ApiResponse(data=serializer.data, message="_(更新成功)")
        except ObjectDoesNotExist:
            return ApiResponse(code=404, message=f"{self.queryset.model.__name__}_(不存在)")
        except ValidationError as e:
            return ApiResponse(code=400, message=e.detail)
        except Exception as e:
            return ApiResponse(code=500, message=f"_(更新失败:) {str(e)}")

    @extend_schema(
        summary="微信用户状态管理",
        description="通过传入不同状态值来管理微信用户状态（0:正常, 1:冻结, 2:注销）",
        parameters=[
            OpenApiParameter(name="wx_id", description="微信用户ID", required=True, location=OpenApiParameter.QUERY),
            OpenApiParameter(name="status", description="用户状态（0:正常, 1:冻结, 2:注销）", required=True,
                             location=OpenApiParameter.QUERY)
        ],
        responses={
            200: {
                "type": "object",
                "properties": {
                    "code": {"type": "integer", "example": 200},
                    "message": {"type": "string", "example": "操作成功"}
                }
            },
            400: {
                "type": "object",
                "properties": {
                    "code": {"type": "integer", "example": 400},
                    "message": {"type": "string", "example": "参数错误"}
                }
            }
        }
    )
    @action(detail=False, methods=['post'], url_path='wx_user_status')
    def wx_user_status(self, request):
        """
        微信用户状态管理
        :param request:
        :return:
        """
        try:
            wx_id = request.data.get("wx_id")
            status = request.data.get('status')
            # 参数校验
            if not wx_id:
                return ApiResponse(code=400, message="_(缺少用户ID参数)")

            if status not in [0, 1, 2]:
                return ApiResponse(code=400, message="_(状态值无效，仅支持0(正常)、1(冻结)、2(注销))")

            # 检查用户是否存在
            try:
                user = WeChatUser.objects.get(id=wx_id)
            except WeChatUser.DoesNotExist:
                return ApiResponse(code=404, message="_(用户不存在)")

            # 更新用户状态
            status_int = int(status)
            user.status = status_int
            user.save()

            # 根据状态返回不同消息
            status_messages = {
                0: "_(用户已恢复正常)",
                1: "_(用户已冻结)",
                2: "_(用户已注销)"
            }
            return ApiResponse(
                data={"user_id": wx_id, "status": status_int},
                message=status_messages[status_int]
            )
        except Exception as e:
            logger.error(f"用户状态管理失败: {str(e)}")
            return ApiResponse(code=500, message=f"_(操作失败: ){str(e)}")

@extend_schema(
    methods=['POST'],
    tags=["微信接口"],
    summary="获取分享人openID",
    description="获取分享人openID",
    request={
        'application/json': {
            'type': 'object',
            'properties': {
                'shareId': {'type': 'string', 'description': '分享人openId'}
            },
            'required': ['shareId']
        }
    },
)
@api_view(['POST'])
def updateWxUser(request):
    """
    1  总分享次数
    2. 分享成功次数
    :return:
    """
    res.clear()
    try:
        if request.method == "POST":
            try:
                logger.info("=======body==========")
                body = json.loads(request.body)
                shardId = body.get("shareId")
                token = request.headers.get("token")
                count = int(getEnvConfig("Is_Actice_count"))
                if not shardId or not token:
                    return JsonResponse(CustomStatus.custom_message(status=CustomStatus.FAIL,
                                                                    custom_msg=_("参数缺失（shareId或token）")))
                token_key = _redis.getKey(token)
                if not token_key:
                    return JsonResponse(CustomStatus.custom_message(status=CustomStatus.FAIL,custom_msg=_("token无效或已过期")))
                has_invitation = InvitationRecord.objects.filter(invitee__open_id=token_key).exists()
                if has_invitation or token_key == shardId:
                    logger.info(f"被邀请人{token_key}已存在邀请记录，跳过计数")
                    return JsonResponse(CustomStatus.custom_message(status=CustomStatus.SUCCESS, custom_msg=_("被邀请人已被邀请，不增加分享计数")))
                try:
                    userData = ChatUser.objects.get(open_id=shardId)
                except ChatUser.DoesNotExist:
                    return JsonResponse(CustomStatus.custom_message(status=CustomStatus.FAIL,
                                                                    custom_msg=_("分享人不存在")))
                old_count = userData.share_success_count
                userData.share_success_count = old_count + 1
                if userData.share_success_count % count == 0:
                    # 重置分享计数
                    userData.share_success_count = 0
                    # allow_count加1（处理None的情况）
                    userData.allow_count = (userData.allow_count or 0) + 1
                userData.save()
            except Exception as e:
                logger.info("参数出错:"+str(e))
            return JsonResponse(CustomStatus.custom_message(status=CustomStatus.SUCCESS, custom_msg=_("更新成功")))
    except Exception as e:
        logger.error(f"更新微信用户失败: {str(e)}")
        return JsonResponse(CustomStatus.custom_message(status=CustomStatus.BAD_REQUEST, custom_msg="更新失败"))


@extend_schema(
    methods=['POST'],
    tags=["微信接口"],
    summary="获取邀请人列表信息",
    description="获取邀请人列表信息",
    request={
        'application/json': {
            'type': 'object',
            'properties': {
                'openId': {'type': 'string', 'description': 'Id'}
            },
            'required': ['openId']
        }
    },
)
@api_view(['POST'])
def getAcquireNewUsers(request):
    """
    获取拉新用户
    :param request:
    :return:
    """
    res.clear()
    if request.method == "POST":
        body = json.loads(request.body)
        openId = body.get("openId")
        userData = ChatUser.objects.get(open_id=openId)
        # 获取该用户的所有邀请记录
        invitation_records = InvitationRecord.objects.filter(inviter=userData).select_related('invitee')
        total_count = invitation_records.count()
        invitees_details = []
        for record in invitation_records:
            invitees_details.append({
                'username': record.invitee.username or '未知用户',
                'openid': record.invitee.open_id,
                'created_at': record.created_at,
                'avatar': record.invitee.user_avatar or '',
                'gender': record.invitee.user_gender or 'unknown'
            })
        data = {
            'total_count': total_count,
            'invitees_list': invitees_details
        }
        return JsonResponse(CustomStatus.SUCCESS.to_response(data=data))
